﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;

#endregion

namespace ScrumTable.Config.ConfigManagement
{


    /// <summary>
    /// Represents the method that handles the ScreenSettingChanged event.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void ScreenSettingChanged(object sender, EventArgs e);

    /// <summary>
    /// Represents a ConfigManager
    /// </summary>
    [XmlRoot(ElementName = "ConfigRoot")]
    public class ConfigManager : ISerializationMarker<ConfigManager>
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private readonly List<Config> _configList = new List<Config>();
        private Config _currentConfig;


        /// <summary>
        /// Occurs when [screen setting changed].
        /// </summary>
        public event ScreenSettingChanged ChangedScreenSettings;

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------


        /// <summary>
        /// Gets pr sets the cultor info (screen language)
        /// </summary>
        [XmlAttribute]
        public string CultureInfo { get; set; }

        /// <summary>
        /// Gets or sets the cultor info (screen language)
        /// </summary>
        [XmlAttribute]
        public bool OnboardKeyboardEnabled { get; set; }

        /// <summary>
        /// Gets or sets the config list.
        /// </summary>
        [XmlArray("ConfigList")]
        [XmlArrayItem(Type = typeof(Config), ElementName = "Config")]
        public List<Config> ConfigList
        {
            get { return _configList; }
        }

        /// <summary>
        /// Gets the deserialized current configuration settings instance.
        /// </summary>
        [XmlIgnore]
        public Config Config
        {
            get
            {
                if (_configList.Count == 0)
                {
                    _configList.Add(new Config(){Id = 0});
                }
                if(_currentConfig == null)
                {
                    _currentConfig = _configList[0];
                }
                return _currentConfig;
            }
            set
            {
                _currentConfig = value;
                if (ChangedScreenSettings != null)
                {
                    ChangedScreenSettings(this, new EventArgs());
                }
            }
        }

        /// <summary>
        /// Contains the serializer
        /// </summary>
        [XmlIgnore]
        public ConfigSerializer<ConfigManager> Serializer { get; set; }

        #endregion

        #region Constructors / Destructor

        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        /// <summary>
        /// DO NOT USE THIS CONSTRUCTOR FROM GLOBAL CODE. THE SERIALIZER NEEDS
        /// A PUBLIC CONSTRUCTOR!
        /// </summary>
        public ConfigManager()
        {
            CultureInfo = "en-US";
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------
        
        /// <summary>
        /// Adds a new Config and sets it as current Config
        /// </summary>
        public void AddAndSetConfig(string name="New Config")
        {
            AddAndSetConfig(ConfigList.Max((x) => x.Id) + 1, name);
        }


        /// <summary>
        /// Adds a new Config and sets it as current Config
        /// </summary>
        internal void AddAndSetConfig(int id, string name = "New Config")
        {
            Config = new Config() { ConfigName = name, Id = id};
            _configList.Add(_currentConfig);
        }

        /// <summary>
        /// Sets the current Config
        /// </summary>
        /// <param name="id">id of this config</param>
        public void SetCurrentConfig(int id)
        {
            var tmpConfig = _configList.Find(x => x.Id == id);
            if(tmpConfig == null)
            {
                tmpConfig = _configList.FirstOrDefault();
                if(tmpConfig == null)
                {
                    AddAndSetConfig(id, "Default Config: Restored");
                    return;
                }
            }
            if(tmpConfig != Config)
            {
                Config = _configList.Find(x => x.Id == id);
            }
        }

        /// <summary>
        /// Deletes the config
        /// </summary>
        /// <param name="config">the config</param>
        public void DeleteConfig(Config config)
        {
            if(Config == config)
            {
                Config = _configList.FirstOrDefault();
            }
            _configList.Remove(config);
        }

        /// <summary>
        /// Saves the config to a file.
        /// </summary>
        public void Save()
        {
            Serializer.Serialize(this);
        }

        /// <summary>
        /// Saves the config to a file.
        /// </summary>
        /// <param name="path">path to store the file.</param>
        public void Save(string path)
        {
            Serializer.Serialize(this);    
            new ConfigSerializer<ConfigManager>(path, path).Serialize(this);
        }

        /// <summary>
        /// Adds to the current config a screen settings. The current setting gets overwritten.
        /// </summary>
        /// <param name="screen"></param>
        /// <param name="type"></param>
        /// <param name="info"></param>
        public void AddScreenSettings(string screen, Type type, string info = null)
        {
            var screenConfig = GetMultiScreenSettings(screen) ??
                               Config.ScreenSettings.Find((x) => x.ScreenNames.Count > 0 && x.ScreenNames[0] == screen);

            
            if (screenConfig != null)
            {
                screenConfig.Args = info;
                screenConfig.SetControlAsString(type);
            }
            else
            {
                Config.ScreenSettings.Add(new ScreenConfig(screen, type){Args = info});
            }
        }


        
        /// <summary>
        /// Adds a new setting for a list of screennames. Old settings gets removed.
        /// </summary>
        /// <param name="screen">a list of screen names</param>
        public void AddScreenSettings(List<string> screen)
        {
            if (screen.Count == 0)
            {
                return;
            }

            //delete all old settings
            foreach(string screenName in screen)
            {
                ScreenConfig screenConfig;
                while((screenConfig = GetMultiScreenSettings(screenName))!=null)
                {
                   Config.ScreenSettings.Remove(screenConfig);
                }
            }
            
            ScreenConfig newConfig = new ScreenConfig();
            newConfig.ScreenNames.AddRange(screen);
            if (newConfig.IsMultiConfig || GetScreenSettings(screen[0])==null)
            {
                Config.ScreenSettings.Add(newConfig);    
            }
            

            if (ChangedScreenSettings != null)
            {
                ChangedScreenSettings(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Fires the ChangedScreenSettings event
        /// </summary>
        public void FireMultiScreenSetting()
        {
            if (ChangedScreenSettings != null)
            {
                ChangedScreenSettings(this, EventArgs.Empty);
            }
        }
            
        /// <summary>
        /// Gets the control for a single screen
        /// </summary>
        /// <param name="screen">Screen name</param>
        /// <returns>ScreenConfig</returns>
        public ScreenConfig GetScreenSettings(string screen)
        {
            if( Config.ScreenSettings.Count == 0)
            {
                return null;
            }
            var screenConfig = Config.ScreenSettings.Find((x) => x.ScreenNames.Count > 0 && x.ScreenNames[0] == screen);

            return screenConfig;
        }

        /// <summary>
        /// Gets the control for a set of screens
        /// </summary>
        /// <param name="screen">Screen name</param>
        /// <returns>ScreenConfig</returns>
        public ScreenConfig GetMultiScreenSettings(string screen)
        {
            if (Config.ScreenSettings.Count == 0)
            {
                return null;
            }
            var screenConfig = Config.ScreenSettings.Find((x) => x.ScreenNames.Count > 0 && x.IsMultiConfig && x.ScreenNames.Find(y=>y==screen) != null);
            if (screenConfig == null)
                return null;
            return screenConfig;
        }

        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion

        
    }
}
